Version 1/060808 of Achievements by Mikael Segercrantz begins here.

"A table-based way to assign scores for actions, rooms and objects."


Chapter 1 - The objects

Section 1(a) - Table of Achievements

Table of Achievements
message		points		used
text		a number	a number


Section 1(b) - Table of Scored Objects

Table of Scored Objects
object		points		used
a thing		a number	a number


Section 1(c) - Table of Scored Places

Table of Scored Places
loci		points		used
a room		a number	a number


Section 1(d) - Globals

Achievement-Init is a number which varies. Achievement-Init is 0.

The achievement maximum score is a number which varies. The achievement maximum score is 0.


Chapter 2 - Rules

Section 2(a) - Overriding the standard rules

Procedural rule: 
    substitute the announce the short score rule for the announce the score rule;
    substitute the announce the final score rule for the print final score rule.


Section 2(b) - Inform 6 replacements

Include (- Constant TASKS_PROVIDED; -) before the library.

Include (- Replace AfterGameOver; -) before the library.

Include (-
[ AfterGameOver i;
   .RRQPL;
   L__M(##Miscellany,5);
   .RRQL;
   print "> ";
   say__p = 0;
   temp_global=0;
#Ifdef TARGET_ZCODE;
   read buffer parse DrawStatusLine;
#Ifnot; ! TARGET_GLULX
   KeyboardPrimitive(buffer, parse);
#Endif; ! TARGET_
   i=parse-->1;
   if (i==QUIT1__WD or QUIT2__WD) quit;
   if (i==RESTART__WD)      @restart;
   if (i==RESTORE__WD)      { RestoreSub(); jump RRQPL; }
   if (i==FULLSCORE1__WD or FULLSCORE2__WD && TASKS_PROVIDED==0)
   {   new_line; (+ announce the achievements rule +)(); jump RRQPL; }
   if (deadflag==2 && i==AMUSING__WD && I7_Amusing_Provided())
   {   new_line; CarryOutActivity(AMUSING_ACT, 0);
       jump RRQPL; }
   if (i==UNDO1__WD or UNDO2__WD or UNDO3__WD)
   {   
#ifdef PREVENT_UNDO;
		print "The use of UNDO is forbidden in this game.^";
		jump RRQPL;
#endif;
  		if (undo_flag==0)
       {   L__M(##Miscellany,6);
           jump RRQPL;
       }
       if (undo_flag==1) jump UndoFailed2;
#Ifdef TARGET_ZCODE;
       @restore_undo i;
#Ifnot; ! TARGET_GLULX
       @restoreundo i;
       i = (~~i);
#Endif; ! TARGET_
       if (i==0)
       {   .UndoFailed2; L__M(##Miscellany,7);
       }
       jump RRQPL;
   }
   L__M(##Miscellany,8);
   jump RRQL;
];
-)


Section 2(c) - Inform 6 to display library messages

Include (-
[ FullScoreBegin;
    if (deadflag) (+ announce the died achievement score rule +)();
    L__M(##FullScore, 1);
];

[ FullScoreThings;
    L__M(##FullScore, 2);
];

[ FullScoreRooms;
    L__M(##FullScore, 3);
];
-)


Section 2(d) - Miscellaneous rules

To pad (n - a number):
    let m be n;
    if n is less than 0
    begin;
        let n be n multiplied by -1;
	let n be n multiplied by 10;
    end if;
    say "  ";
    if n is less than 10
    begin;
        say "   ";
    otherwise;
        if n is less than 100
	begin;
	    say "  ";
	otherwise;
	    if n is less than 1000, say " ";
	end if;
    end if;
    say m;
    say " ".


Section 2(e) - Full score replacement rules

This is the announce the died achievement score rule:
    say "In that game you scored [score] out of a possible [achievement maximum score], in [turn count] turns.[line break]".

To announce the beginning of full score:
    (- FullScoreBegin(); -).

To announce the tabled part of full score:
    repeat through the Table of Achievements in used order
    begin;
        if the used entry is greater than 0
	begin;
	    let n be the points entry;
	    pad n;
	    say "for [message entry][line break]";
	end if;
    end repeat.

To announce the tabled objects of full score:
    let total be 0;
    repeat through the Table of Scored Objects
    begin;
        if the used entry is not 0, increase the total by the points entry;
    end repeat;
    if total is not 0
    begin;
        pad total;
	say "for ";
	announce the end of objects in full score;
    end if.

To announce the end of objects in full score:
    (- FullScoreThings(); -).

To announce the tabled rooms of full score:
    let total be 0;
    repeat through the Table of Scored Places
    begin;
        if the used entry is not 0, increase the total by the points entry;
    end repeat;
    if total is not 0
    begin;
        pad total;
	say "for ";
        announce the end of rooms in full score;
    end if.

To announce the end of rooms in full score:
    (- FullScoreRooms(); -).

To announce the end of full score:
    pad score;
    say "(out of [achievement maximum score])[line break]".

To announce the no score:
    say "You have not received any points yet."


Section 2(f) - Announce the achievements rule

This is the announce the achievements rule:
    if the score is greater than 0
    begin;
        announce the beginning of full score;
        announce the tabled part of full score;
        announce the tabled objects of full score;
        announce the tabled rooms of full score;
        announce the end of full score;
    otherwise;
        announce the no score;
    end if.


Section 2(g) - Replacing "score"

This is the announce the short score rule:
    say "You have so far scored [score] out of a possible [achievement maximum score], in [turn count] turn[s]."

This is the announce the final score rule:
    say "In that game you scored [score] out of a possible [achievement maximum score], in [turn count] turn[s]."


Section 2(h) - Score achievement

To score the achievement with message (msg - text):
    choose row with message of msg in the Table of Achievements;
    if the used entry is 0
    begin;
        change the used entry to the turn count;
	increase the score by the points entry;
    end if.


Section 2(i) - Score objects

To score found objects:
    repeat through the Table of Scored Objects
    begin;
        if the used entry is 0
	begin;
	    if the player encloses the object entry
	    begin;
	        change the used entry to the turn count;
		increase the score by the points entry;
	    end if;
	end if;
    end repeat.


Section 2(j) - Score rooms

To score visited rooms:
    repeat through the Table of Scored Places
    begin;
        if the used entry is 0
	begin;
	    if the location is the loci entry
	    begin;
	        change the used entry to the turn count;
		increase the score by the points entry;
	    end if;
	end if;
    end repeat.


Section 2(k) - Initialization

To perform initialization:
    let the total be 0;
    repeat through the Table of Scored Places
    begin;
        change the used entry to 0;
	increase the total by the points entry;
	if the loci entry is the location
	begin;
	    change the used entry to -1;
	    increase the score by the points entry;
	end if;
    end repeat;
    repeat through the Table of Scored Objects
    begin;
        change the used entry to 0;
	increase the total by the points entry;
	if the object entry is enclosed by the player
	begin;
	    change the used entry to -1;
	    increase the score by the points entry;
	end if;
    end repeat;
    repeat through the Table of Achievements
    begin;
        increase the total by the points entry;
        change the used entry to 0;
    end repeat;
    change the achievement maximum score to the total.

Before printing the name of a room:
    if Achievement-Init is 0
    begin;
        perform initialization;
	change Achievement-Init to 1;
    end if.


Section 2(l) - Every turn

Every turn (this is the scoring of rooms and objects rule):
    score found objects;
    score visited rooms.


Section 2(m) - Decisions

To decide whether the achievement (txt - text) is scored:
    repeat through the Table of Achievements
    begin;
        if the message entry is txt
	begin;
	    if the used entry is not 0, decide yes;
	end if;
    end repeat;
    decide no.

To decide whether the object (obj - a thing) is scored:
    repeat through the Table of Scored Objects
    begin;
        if the object entry is obj
	begin;
	    if the used entry is not 0, decide yes;
	end if;
    end repeat;
    decide no.

To decide whether the room (rm - a room) is scored:
    repeat through the Table of Scored Places
    begin;
        if the loci entry is rm
	begin;
	    if the used entry is not 0, decide yes;
	end if;
    end repeat;
    decide no.


Chapter 3 - Vocabulary

Section 3(a) - Full score

Understand "full score" or "full" or "fullscore" as requesting the full score.
Requesting the full score is an action out of world.
Carry out requesting the full score: follow the announce the achievements rule.


Achievements end here.

---- Documentation ----

The Achievements extension allows for ease of scoring in a game. It allows for different achievements to be scored, as well as finding certain items and rooms. All the achievements, items, and rooms for scoring are managed through tables; the Table of Achievements, the Table of Scored Objects, and the Table of Scored Places respectively.

The extension defines two global variables:
	1. a number which varies called Achievement-Init. This is used for the extension to know if it has been initialized or not, since it needs to initialize itself when beginning the description of the first location in the game (when play begins does not work, unfortunately, since the location of the player during it is the dark room, not the real location). Initialization grants the points from the start room, if it has any, as well as of any objects enclosed by the player at the beginning of the game, if any have scores defined on them. The name has been chosen to minimize the risk of clashing with a variable in user code.
	2. a number which varies called the achievement maximum score, which is automatically calculated at initialization time.

To use the extension, you need to continue the tables you want to use.

The Table of Scored Objects is defined as follows:

	Table of Scored Objects
	object		points		used
	a thing		a number	a number

The Table of Scored Objects contain the objects for which a score will be given. The object column is the name of the object, the points column the value of the object, and the used column (which will be initialized to 0 at the start of the game) marks the fact of having received the points from the object.

The Table of Scored Places is defined as follows:

	Table of Scored Places
	loci		points		used
	a room		a number	a number

As with the Table of Scored Objects, the Table of Scored Places has the same function. The loci column defining the room to be scored replaces the object column. The used column will be initialized to 0 automatically.

The Table of Achievements is defined as follows:

	Table of Achievements
	message		points		used
	text		a number	a number

Again, the table looks like the previous tables, and again, the used column will be initialized to 0 automatically. The message contains the text which will be shown while listing the full score.

To score an achievement, you need to use the following syntax:

	score the achievement with message "the message entry";

and the points will be added to the score.

It is possible to test if an achievement, an object or a room has been scored, using the phrases

	the achievement "<message>" is scored
	the item <object> is scored
	the room <room> is scored

where <message> is the message entry used to score the achievement, <object> is the item tested for and <room> is the room tested for.

If needed, you may override the every turn rule, "scoring of rooms and objects".

The extension replaces the score and the full score handling of Inform 7, including the final score displaying, to manage the listing of scores from the tables, and contains a little bit of code in Inform 6 - code neutral to the Z-machine and Glulx.

Example: ** Where ever thou art - Demonstrating the use of achievements, locations scored and items scored.

	"Where ever thou art"

	Include Achievements by Mikael Segercrantz.

Let's create the three rooms first.

	The entrance hall is a room. The basement is a room. The dining hall is a room.

Add a door and the connections:

	A wooden door is a door. It is west of the entrance hall and east of the dining hall. It is closed and openable.

	The basement is below the entrance hall.

Add some treasure:

	A baseball cap is a thing. Some crates are in the basement. They are fixed in place.

	Instead of searching the crates for the first time:
		now the baseball cap is in the basement;
		say "Tucked behind crates of various things, you find a baseball cap!"
	
	After opening the wooden door, score the achievement with message "finding the way to the dining hall".

And the tables:

	Table of Achievements (continued)
	used		points		message
	0		10		"finding the way to the dining hall"

	Table of Scored Places (continued)
	used		points		loci
	0		5		basement
	0		5		dining hall

	Table of Scored Objects (continued)
	used		points		object
	0		5		baseball cap

Initialize status line:

	When play begins:
		change the right hand status line to "[score] out of [achievement maximum score]".

Ending the game:

	Every turn:
		if the score is the achievement maximum score, end the game in victory.

And finally the testing command:

	Test me with " open door / w / e / d / search crates / take cap ".